package com.apes.scm.masterdata.product.service;

import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.cache.Cache;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.repository.TaxRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Classify;
import com.apes.scm.masterdata.product.repository.ClassifyRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toMap;


/**
 * 功能：商品分类 Service
 *
 * @author HuJianlin
 * @create 2018-03-15 14:35
 */
@Service("classifyService")
public class ClassifyService extends DomainService {

    @Autowired
    ClassifyRepository classifyRepository;
    @Autowired
    private Cache cache;

    private static final String CONST_DEFAULT_CACHE_NAME = "classifyCache";
    private static final String CONST_DEFAULT_CACHE_KEY_NAME = "classify";
    private static final String CONST_DEFAULT_CACHE_NAME_INIT_FLAG = "classifyCacheInitFlag";

    public Classify save(SimpleRequest request) {
        Classify classify = request.getO(Classify.class);
        Classify classify1 = classifyRepository.saveAndFlush(classify);
        clearCache(classify1);
        return classify1;
    }

    /**
     * 功能：查询
     *
     * @param request
     */
    public Page<Classify> findAll(SimpleRequest request) {
        List<Map> filters = request.get("condition");
        return classifyRepository.findAll(JpaDsl.toCriteria(filters), PageRequest.of(request.get("page"), request.get("size")));
    }


    public Page<Classify> find(SimpleRequest request) {
        return classifyRepository.find(request.get("key"), PageRequest.of(request.get("page"), request.get("size")));
    }

    public Classify update(SimpleRequest request) {
        checkData(request);
        Classify classify = request.getO(Classify.class);
        return classifyRepository.saveAndFlush(classify);
    }

    /**
     * 检查数据判断，判读当前的输入版本信息
     *
     * @param request
     */
    public void checkData(SimpleRequest request) {
        String id = request.get("id");
        int version = request.get("version");

        // 从数据库中取数，检查数据
        Classify classify = classifyRepository.findOne(id);
        if (classify == null) throw new RuntimeException("【" + id + "】在系统中不存在。");
        if (classify.getVersion() != version) throw new RuntimeException("记录已更新或已删除，请重新提交！");
    }

    public String delete(SimpleRequest request) throws Exception {
        String id = request.get("id");
        Integer versions = request.get("version");
        Classify classify = classifyRepository.findOne(id);
        if (classify == null) throw new RuntimeException("商品分类【" + id + "】在系统中不存在。");
        if (classify.getVersion() != versions) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        try {
            classifyRepository.delete(classify);
        } catch (Exception e) {
            throw new Exception("该商品分类已被上级分类或者商品引用，不能删除");
        }
        clearCache(classify);
        return "删除成功";
    }

    /**
     * 回调数据中心品类信息
     *
     * @param request
     */
    public void receiveSave(SimpleRequest request) {
        Map map = request.getMap();
        Classify classify = classifyRepository.findOne(map.get("id").toString());
        if (classify == null) {
            classify = new Classify();
            classify.setId(map.get("id").toString());
        }
        classify.setName(map.get("name").toString());
        if (map.containsKey("taxId")) {
            Tax tax = SpringManager.getBean(TaxRepository.class).findOne(JpaDsl.toCriteriaByEq("origin", map.get("taxId"))).orElse(null);
            classify.setTax(tax);
        }
        if (map.containsKey("superiorId")) {
            classify.setParents(classifyRepository.findOne((String) map.get("superiorId")));
        }
        classify.setLevels(Integer.parseInt(map.get("rank").toString()));
        classify.setValid((boolean) map.get("valid"));
        classify.setLastStage((boolean) map.get("lastTag"));
        classify.setPath(classify.getPath());
//        if (map.containsKey("serveCategoryId")) {
//            classify.setServeCategory(SpringManager.getBean(ServeTypeRepository.class).findOne(map.get("serveCategoryId").toString()));
//        }
        classifyRepository.save(classify);

    }

    public List<Map> findTreeNode(SimpleRequest request) {

        boolean lastStage = (Boolean) request.getMap().get("lastStage");
        Boolean init = (Boolean) cache.get(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_NAME_INIT_FLAG);
        List<Map> treeData;
        if (init == null || !init) {
            treeData = classifyRepository.findTreeData();
            cache.put(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_KEY_NAME, treeData);
            cache.put(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_NAME_INIT_FLAG, true);
        } else {
            treeData = (List<Map>) cache.get(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_KEY_NAME);
        }
        //按父级分组，顶级分类 key 给定 parent
        Map<String, List<Map>> parentsMap = treeData.stream().collect(Collectors.groupingBy(m -> {
            if (m.get("parentsId") == null) {
                return "parent";
            }
            return m.get("parentsId").toString();
        }));
        //遍历分组
        List<Map> collect = parentsMap.get("parent").stream().map(classify -> {
            Map map = new HashMap();
            map.put("title", classify.get("name"));
            map.put("key", classify.get("id"));
            map.put("valid", classify.get("valid"));
            if (lastStage) {
                map.put("disabled", true);
            }
            if (parentsMap.get(classify.get("id")) != null) {
                map.put("children", children(classify.get("id").toString(), parentsMap, lastStage));
            }
            return map;
        }).collect(Collectors.toList());


        return collect;
    }

    /**
     * 递归将值按前端格式返回
     *
     * @param parents
     * @param parentsMap
     * @return
     */
    public List<Map> children(String parents, Map<String, List<Map>> parentsMap, boolean lastStage) {
        List<Map> maps = new ArrayList<>();
        parentsMap.get(parents).forEach(map -> {
            Map result = new HashMap();
            result.put("title", map.get("name"));
            result.put("key", map.get("id"));
            result.put("valid", map.get("valid"));
            if (parentsMap.containsKey(map.get("id")
            )) {
                result.put("children", children(map.get("id").toString(), parentsMap, lastStage));
                if (lastStage) {
                    result.put("disabled", true);
                }
            }
            result.put("isLeaf", map.get("lastStage"));
            maps.add(result);
        });
        return maps;
    }

    /**
     * 商品分类树形展示
     *
     * @param simpleRequest
     * @return
     */
    public List<Map> findTreeData(SimpleRequest simpleRequest) {
        Boolean init = (Boolean) cache.get(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_NAME_INIT_FLAG);
        List<Map> treeData;
        if (init == null || !init) {
            treeData = classifyRepository.findTreeData();
            cache.put(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_KEY_NAME, treeData);
            cache.put(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_NAME_INIT_FLAG, true);
        } else {
            treeData = (List<Map>) cache.get(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_KEY_NAME);
        }
        Map<String, Map> collect = treeData.stream().collect(toMap(map -> map.get("id").toString(), map -> map, (k1, k2) -> k1));
        treeData.forEach(data -> {
            if (data.get("parentsId") != null) {
                data.put("path", recursionPath(collect, data.get("parentsId").toString(), data.get("id").toString()));
            } else {
                data.put("path", data.get("id").toString());
            }
        });
        return treeData;
    }

    /**
     * 商品分类树形展示(有效的)
     *
     * @param simpleRequest
     * @return
     */
    public List<Map> findTreeDataByValid(SimpleRequest simpleRequest) {
        List<Map> treeNode = this.findTreeNode(simpleRequest);
        return filterClassifyInvalid(treeNode);
    }

    public String recursionPath(Map<String, Map> collect, String id, String path) {
        path = id + "/" + path;
        if (collect.get(id).get("parentsId") != null) {
            return recursionPath(collect, collect.get(id).get("parentsId").toString(), path);
        }
        return path;
    }
    @OutboxSubscriber(name = "清除分类缓存", aggregateType = "com.apes.scm.masterdata.product.model.Classify")
    public void clearCache(Classify classify) {
        cache.remove(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_KEY_NAME);
        cache.remove(CONST_DEFAULT_CACHE_NAME, CONST_DEFAULT_CACHE_NAME_INIT_FLAG);
    }

    public List<Map> filterClassifyInvalid(List<Map> treeNode) {
        List<Map> newMap = new ArrayList();
        for (Map map : treeNode) {
            Boolean isLeaf = map.get("isLeaf") != null ? Boolean.valueOf(map.get("isLeaf").toString()) : false;
            Boolean valid = Boolean.valueOf(map.get("valid").toString());
            if (isLeaf) {
                if (valid) newMap.add(map);
            } else {
                if (valid) {
                    List<Map> children;
                    if (map.get("children") != null ) {
                        children = this.filterClassifyInvalid((List<Map>) map.get("children"));
                    } else children = new ArrayList<>();
                    map.put("children", children);
                    newMap.add(map);
                }
            }
        }
        return newMap;
    }
}
